package user.post.comment;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import Search.SearchFacade;
import sessionManager.SessionManager;
import user.post.Post;

import exceptions.comment.NonExistentCommentException;

/**
 * Essa classe gerencia os comentarios, que pode ser usada por um post.
 * Delegando as funcoes de busca adicao de comentarios ao pacote comments. Note
 * que ela possui metodos relativos ao gerenciamento de comments e sub coments,
 * pois comment possui diversos subcomments. Armazena as informacoes
 * internamento na forma de um {@code ArrayList}.
 * 
 * @author Heitor Meira
 * 
 */
public class CommentManager implements Serializable {
	
	private static final long serialVersionUID = -8613888443841373480L;
	private List<Comment> comments;
	private SessionManager session;
	private SearchFacade search;
	/**
	 * O contrutor desse gerencidor de comentarios apenas instancia um {@code
	 * ArrayList} de {@code Comment} vazio.
	 */
	public CommentManager() {
		comments = new ArrayList<Comment>();
		session =  SessionManager.getInstance();
		search  = new SearchFacade();
	}

	/**
	 * Fornece o numero de subcomentarios imediatos de um comentario genrenciado
	 * por esse gereciador.
	 * 
	 * @param commentId
	 *            A identificacao do comentario que se quer saber quantos
	 *            subcomentarios ele possui.
	 * @return A quantidade de subcomentario que o comentario encontrado possui.
	 * @throws NonExistentCommentException
	 *             Se nenhum comentario com a idetificacao fornecida for
	 *             encontrado.
	 */
	public int getNumberOfSubComments(String commentId) throws NonExistentCommentException {
		
		Comment comment = findCommentByID(commentId);
		
		
		if(comment == null)				
			throw new NonExistentCommentException("There is no comment with this id."+commentId);
		
		
		return comment.getComments().size();
	}
	
	/**
	 * Fornece o numero de todos os subcomentarios de um comentario genrenciado
	 * por esse gereciador.
	 * 
	 * @param commentId
	 *            A identificacao do comentario que se quer saber quantos
	 *            subcomentarios ele possui.
	 * @return A quantidade de subcomentario que o comentario encontrado possui.
	 * @throws NonExistentCommentException
	 *             Se nenhum comentario com a idetificacao fornecida for
	 *             encontrado.
	 */
	public int getNumberOfAllSubComments(String commentId) throws NonExistentCommentException {
		Comment comment = findCommentByID(commentId);
		
		if(comment == null) {
			throw new NonExistentCommentException("There is no comment with this id.");
		}
		return count(comment, 0);
	}

	/**
	 * Adiciona um comentario a esse gerenciador de comentarios.
	 * 
	 * @param author
	 *            O autor do comentario.
	 * @param text
	 *            O texto do comentario.
	 * @return A idetificacao do comentario adicionado.
	 */
	public String addComment(String author, String text) {
		Comment newComment = new Comment(text, author);
		comments.add(newComment);
		return newComment.getId();
	}
	
	/**
	 * 
	 * Adiciona um comentario a esse gerenciador de comentarios.
	 * @param author O autor do comentario.
	 * @param text O texto do comentario.
	 * @param commentId
	 * @return A idetificacao do comentario adicionado.
	 * @throws NonExistentCommentException Se nenhum {@code Comment} com a identificacao fornecida for encontrado.
	 */
	public String addSubComment(String author, String text, String commentId) throws NonExistentCommentException {
		Comment commentParent = findCommentByID(commentId);
		if(commentParent == null) {
			throw new NonExistentCommentException("There is no comment with this id.");
		}
		return commentParent.addComment(author, text);
	}

	/**
	 * Faz uma busca em todos os comentarios e subcomentarios desse gerenciador
	 * de comentarios.
	 * 
	 * Faz busca recursiva
	 * @param id
	 *            A idetificacao do comentario ou subcomentario.
	 * @return O {@code Comment} com a identificacao fornecida.
	 * @throws NonExistentCommentException
	 *             Se nenhum {@code Comment} com a idetificacao fornecida for
	 *             encontrado.
	 */
	public Comment findCommentByID(String id) throws NonExistentCommentException {
		
		
		for(Post post : search.getAllPosts())
		for(Comment ct : post.getCommentManager().getComments()){			
			if(ct.getId().equals(id))			
				return ct;			
			
			else{					
				
				List<Comment> comts = find(ct,"ID",id);				
				
				for(Comment coment : comts){
					
					if(coment.getId().equals(id))					
						return coment;
					
				}
				
			}
		}
		
		return null;
	}

	
	/**
	 * Faz uma busca por um comentario ou subcomentario em todos os coments e
	 * subcomentarios da lista fornecida.
	 * 
	 * @param comments
	 *            A lista de comentarios por onde comecar a procurar.
	 * @param id
	 *            A identficaco do comentario que se esta buscando.
	 * @param comment
	 *            Esse comentario eh usado internamente pra facilitar as
	 *            recursoes, no inicio ele deve ser {@code null} ou um
	 *            comentario default caso nenhum comentario seja encontrado.
	 * @return O comentario buscado, ou o {@code Comment} default passado como
	 *         argumento.
	 */
	private List<Comment> find(Comment comment, String type, String tag) {
		List<Comment> ctFind = new ArrayList<Comment>();
		
		if(comment.getComments().size() == 0)		
			return ctFind;
		
		for(Comment ct : comment.getComments()){
		
			if(type.equals("ID")){
				ctFind.add(ct);
				if (ct.getId().equals(tag))					
					return ctFind;
				
				
				ctFind.addAll(find(ct,type,tag));
				
			}
			else if (type.equals("")){
				ctFind.add(ct);
				ctFind.addAll(find(ct,type,tag));

			}
		}
		
			
		return ctFind;
	}	
	
	/**
	 * Fornece todos os comentarios imediatos desse gerenciador.
	 * 
	 * @return Uma lista de comentarios.
	 */
	public List<Comment> getComments() {
		return comments;
	}
	
	/**
	 * Fornece a quantidade total de subcomentarios existente em um comentario.
	 * Esse paramentro inteiro recebido deve ser sempre zero, ele eh usado
	 * internamente para facilitar as recursoes.
	 * 
	 * @param comment
	 *            O comentario ou subcomentario que se quer saber quantos
	 *            comentario e subcomentario tem.
	 * @param count
	 *            Esse parametro eh usado internamente para facilitar a
	 *            recursao, ele deve inciar em zero ou outro valor default caso
	 *            nao tenha nenhum subcometario.
	 * @return A quantidade de subcoments ou o valor default passado como
	 *         argumento caso nao eixista nenhum subcoment.
	 */
	private int count(Comment comment, int count) {
		Iterator<Comment> itComments = comment.getComments().iterator();
		while(itComments.hasNext()) {
			itComments.next();
			count++;
		}
		
		itComments = comment.getComments().iterator();
		
		while(itComments.hasNext()) {
			Comment tmpComment = itComments.next();
			if(tmpComment != null) {
				count = count(tmpComment, count);
			}
		}
		
		return count;
	}
	
	

	
		
}
